<script setup>
import LogicFlow from '@logicflow/core'
import {SelectionSelect, Snapshot} from '@logicflow/extension'
import '@logicflow/core/dist/style/index.css'
import '@logicflow/extension/lib/style/index.css'
import DiagramToolbar from './DiagramToolbar.vue'
import DiagramSidebar from './DiagramSidebar.vue'
import PropertyPanel from './PropertyPanel.vue'
import {registerCustomElement} from './node'
import {ref, reactive, onMounted, nextTick, watch} from 'vue'
import {debounce} from "@/utils/tools.ts";

/**
 * @type {Object<UnwrapRef<LogicFlow>>}
 */
const lf = ref(null)
const activeNodes = ref([])
const activeEdges = ref([])
const properties = reactive({})
const diagram = ref(null)
const emits = defineEmits(['saveGraph'])

const props = defineProps({
  data: {
    type: Object,
    default: {
      nodes: [],
      edges: [],
    },
  },
  isSilentMode: {
    type: Boolean,
    default: false,
  },
})

watch(
    () => props.data,
    (val) => {
      lf.value = null
      nextTick(() => {
        initLogicFlow(val)
      })
    },
    {deep: true}
)

onMounted(() => {
  initLogicFlow(props.data)
})

const initLogicFlow = (data) => {
  // 引入框选插件
  LogicFlow.use(SelectionSelect)
  // 引用导出插件
  LogicFlow.use(Snapshot)
  const lf_ = new LogicFlow({
    container: diagram.value,
    overlapMode: 1,
    autoWrap: true,
    metaKeyMultipleSelected: true,
    keyboard: {
      enabled: true,
    },
    grid: {
      visible: false,
      size: 5,
    },
    background: {
      backgroundImage:
          'url("")',
      backgroundRepeat: 'repeat',
    },
    isSilentMode: props.isSilentMode,
  })
  lf_.setTheme({
    baseEdge: {strokeWidth: 1},
    baseNode: {strokeWidth: 1},
    nodeText: {overflowMode: 'autoWrap', lineHeight: 1.5},
    edgeText: {
      overflowMode: 'autoWrap',
      lineHeight: 1.5,
      textWidth: 0,
      background: {fill: '#d1fad6', wrapPadding: '2px,5px'},
    },
  })
  // 注册自定义元素
  registerCustomElement(lf_)
  lf_.setDefaultEdgeType('pro-polyline')
  lf_.render(data)
  lf.value = lf_
  lf.value.on('selection:selected,node:click,blank:click,edge:click', () => {
    nextTick(() => {
      const {nodes, edges} = lf.value.getSelectElements()
      activeNodes.value = nodes
      activeEdges.value = edges
      $_getProperty()
    })
  })
  lf.value.on('text:update,edge:add,edge:delete,edge:exchange-node,edge:adjust,node:add,node:delete,node:drop,node:dnd-add', debounce(() => {
    $_saveGraph()
  }, 800))
}
// 获取可以进行设置的属性
const $_getProperty = () => {
  let _properties = {}
  const {nodes, edges} = lf.value.getSelectElements()
  nodes.forEach((node) => {
    _properties = {...node.properties}
  })
  edges.forEach((edge) => {
    _properties = {...edge.properties}
  })
  const _properties_keys = Object.keys(_properties)
  _properties_keys.forEach((key) => {
    properties[key] = _properties[key]
  })
  Object.keys(properties).forEach(key => {
    if (_properties_keys.indexOf(key) < 0) {
      delete properties[key]
    }
  })
  return properties
}

const $_dragInNode = (type) => {
  lf.value.dnd.startDrag({
    type,
  })
}

const $_changeNodeFill = (color) => {
  const {nodes} = lf.value.graphModel.getSelectElements()
  nodes.forEach(({id}) => {
    lf.value.setProperties(id, {
      fill: color,
    })
  })
}

const $_updateText = (text) => {
  activeNodes.value.forEach(({id}) => {
    const nodeModel = lf.value.getNodeModelById(id)
    nodeModel.updateText(text)
    nextTick(() => {
      $_saveGraph()
    })
  })
}

const $_setStyle = (item) => {
  activeNodes.value.forEach(({id}) => {
    lf.value.setProperties(id, item)
  })
  activeEdges.value.forEach(({id}) => {
    lf.value.setProperties(id, item)
  })
  $_getProperty()
}

const $_setZIndex = (type) => {
  activeNodes.value.forEach(({id}) => {
    lf.value.setElementZIndex(id, type)
  })
  activeEdges.value.forEach(({id}) => {
    lf.value.setElementZIndex(id, type)
  })
}

const $_saveGraph = () => {
  const data = lf.value.getGraphData()
  emits('saveGraph', data)
}
</script>
<template>
  <div class="diagram">
    <diagram-toolbar
        class="diagram-toolbar"
        v-if="lf && !props.isSilentMode"
        :lf="lf"
        :activeEdges="activeEdges"
        @changeNodeFillColor="$_changeNodeFill"
        @saveGraph="$_saveGraph"
    />
    <div class="diagram-main">
      <div class="diagram-container" ref="container">
        <div class="diagram-wrapper">
          <div class="lf-diagram" ref="diagram"></div>
        </div>
      </div>
      <diagram-sidebar class="diagram-sidebar" @dragInNode="$_dragInNode"/>
    </div>
    <!-- 右侧属性面板 -->
    <PropertyPanel
        class="diagram-panel"
        v-if="activeNodes.length > 0 || activeEdges.length > 0"
        :onlyEdge="activeNodes.length === 0"
        :elementsStyle="properties"
        :is-text-node="activeNodes.length > 0 && activeNodes[0].type === 'pro-text'"
        @setStyle="$_setStyle"
        @setText="$_updateText"
        @setZIndex="$_setZIndex"
    />
  </div>
</template>

<style scoped>
.diagram {
  position: relative;
  width: 100%;
  height: calc(100vh - 62px);
}

.diagram * {
  box-sizing: border-box;
}

.diagram-toolbar {
  position: absolute;
  top: 0;
  padding-left: 10px;
  left: 0;
  height: 40px;
  width: 340px;
  display: flex;
  align-items: center;
  border-bottom: 1px solid #e5e5e5;
  z-index: 10;
  background: #e5e5e5;
}

.diagram-main {
  display: flex;
  width: 100%;
  height: 100%;
}

.diagram-sidebar {
  width: 185px;
  height: calc(100% - 40px);
  padding: 10px;
}

.diagram-panel {
  width: 300px;
  background: #fff;
  height: calc(100% - 2px);
  position: absolute;
  right: 186px;
  top: 1px;
  border-left: 1px solid #e5e5e5;
}

.diagram-container {
  flex: 1;
}

/* 由于背景图和gird不对齐，需要css处理一下 */
/*.diagram /deep/ .lf-background {
  left: -9px;
}*/
.diagram-wrapper {
  box-sizing: border-box;
  width: 100%;
  height: 100%;
}

.lf-diagram {
  /*box-shadow: 0 0 4px #838284;*/
  width: 100%;
  height: 100%;
  border-right: 1px solid #dedede;
  border-bottom: 1px solid #dedede;
}

::-webkit-scrollbar {
  width: 9px;
  height: 9px;
  background: white;
  border-left: 1px solid #e8e8e8;
}

::-webkit-scrollbar-thumb {
  border-width: 1px;
  border-style: solid;
  border-color: #fff;
  border-radius: 6px;
  background: #c9c9c9;
}

::-webkit-scrollbar-thumb:hover {
  background: #b5b5b5;
}
</style>
